package com.ljw.gulimall.authserver.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.gson.Gson;
import com.ljw.common.constant.AuthServiceConstant;
import com.ljw.common.exception.BizCodeEnum;
import com.ljw.common.utils.GetCookieUtils;
import com.ljw.common.utils.JwtUtils;
import com.ljw.common.utils.R;
import com.ljw.common.vo.UserLoginWxVo;
import com.ljw.gulimall.authserver.feign.MemberFeignService;
import com.ljw.gulimall.authserver.feign.ThirdPartFeignService;
import com.ljw.gulimall.authserver.utils.ConstantWxUtils;
import com.ljw.gulimall.authserver.utils.HttpClientUtils;
import com.ljw.gulimall.authserver.utils.RandomUtil;
import com.ljw.gulimall.authserver.vo.MemberVo;
import com.ljw.gulimall.authserver.vo.UserLoginVo;
import com.ljw.gulimall.authserver.vo.UserRegistVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Controller
public class LoginController {

    @Autowired
    private ThirdPartFeignService thirdPartFeignService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MemberFeignService memberFeignService;


    @GetMapping("/testLogin")
    public String testLogin(HttpServletResponse response){
        Cookie cookie = new Cookie("test","123456");
        cookie.setDomain("gulimall.com");
        response.addCookie(cookie);
//        session.setAttribute("test","123456");
//        Object test = session.getAttribute("test");
//        System.out.println(test);
        return "redirect:http://gulimall.com";
    }

    @GetMapping("/sms/sendCode")
    @ResponseBody
    public R sendCode(@RequestParam("phone") String phone) {

        //1、接口防刷
        String redisCode = redisTemplate.opsForValue().get(AuthServiceConstant.SMS_CODE_CACHE_PREFIX + phone);
        if (!StringUtils.isBlank(redisCode)){
            String[] split = redisCode.split("_");
            //保存的时候是秒为单位，所谓*1000
            Long saveTime = Long.parseLong(split[1]);
            Long currentTime = System.currentTimeMillis();
            Long compareTime = currentTime - saveTime;
            if (compareTime < 60000){
                return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_CODE_EXCEPTION.getMessage());
            }
        }

        String code = RandomUtil.getSixBitRandom();

        //发送短信
        R r = thirdPartFeignService.sendCode(phone, code);
        //判断发送短信是否成功
        String msg = (String) r.get("msg");
        if (StringUtils.equals(msg, "success")){

            redisTemplate.opsForValue().set(AuthServiceConstant.SMS_CODE_CACHE_PREFIX + phone, code + "_" + System.currentTimeMillis(), 10, TimeUnit.MINUTES);

            return R.ok();
        }
        else {
            return R.error("发送短信失败");
        }
    }

    @PostMapping("/regist")
    public String regist(@Valid UserRegistVo userRegistVo, BindingResult result, RedirectAttributes redirectAttributes){

        //判断校验的数据是否存在错误
        if (result.hasErrors()){
            Map<String, String> errors = result.getFieldErrors().stream()
                    .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/reg.html";
        }

        //真正注册，调用远程服务进行注册
        //1、校验验证码
        String code = userRegistVo.getCode();
        String redisKey = AuthServiceConstant.SMS_CODE_CACHE_PREFIX + userRegistVo.getPhone();
        String redisCode = redisTemplate.opsForValue().get(redisKey);
        if (!StringUtils.isEmpty(redisCode) && code.equals(redisCode.split("_")[0])){
            //删除验证码;
            redisTemplate.delete(redisKey);

            //验证码通过 //调用远程服务进行注册
            R r = memberFeignService.regist(userRegistVo);
            if (r.getCode() == 0){
                //成功
                return "redirect:http://auth.gulimall.com/login.html";
            }
            else{
                Map<String,String> errors = new HashMap<>();
                errors.put("msg", r.getData("msg",new TypeReference<String>(){}));
                redirectAttributes.addFlashAttribute("errors", errors);
                return "redirect:http://auth.gulimall.com/reg.html";
            }
        }
        else {
            Map<String, String> errors = new HashMap<>();
            errors.put("code", "验证码错误");
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/reg.html";
        }

    }

    @PostMapping("/login")
    public String login(UserLoginVo userLoginVo, RedirectAttributes redirectAttributes, HttpServletResponse response){
        //1、远程调用登入接口
        R login = memberFeignService.login(userLoginVo);
        //2、是否登入成功
        if (login.getCode() == 0){
            //登入成功，获取登入用户的信息
            MemberVo memberInfo = login.getData("memberInfo", new TypeReference<MemberVo>() {
            });
            //登入用户的id转换成string类型
            String memberId = memberInfo.getId().toString();
            //查看redis中是否保存该用户信息
            String memberInfoJsonRedis = redisTemplate.opsForValue().get(memberId);
            //redis中不存在该用户，则保存该用户的信息到redis中去，并把token存在cookie中
            if (memberInfoJsonRedis == null){
                //转换成json字符串存进redis中
                memberInfo.setPassword(null);
                String memberInfoJson = JSON.toJSONString(memberInfo);
                //用户的个人信息在redis中有效期为30分钟
                redisTemplate.opsForValue().set(memberId, memberInfoJson, 30, TimeUnit.MINUTES);
            }
            String jwtToken = JwtUtils.getJwtToken(memberId);
            Cookie cookie = new Cookie(AuthServiceConstant.LOGIN_USER, jwtToken);
            cookie.setDomain("gulimall.com");
            cookie.setMaxAge(AuthServiceConstant.USER_TIMEOUT);
            response.addCookie(cookie);
            return "redirect:http://gulimall.com";
        }
        else {
            Map<String,String> errors = new HashMap<>();
            errors.put("msg", login.getData("msg", new TypeReference<String>(){}));
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }

    @GetMapping("/wxLogin")
    public String wxLogin(){
        // 微信开放平台授权baseUrl  %s相当于?代表占位符
        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                "?appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +
                "#wechat_redirect";
        String redirectUrl = ConstantWxUtils.WX_REDIRECT_URL;
        try {
             redirectUrl = URLEncoder.encode(redirectUrl,"utf-8");
        }catch (Exception e){
            e.printStackTrace();
        }
        String url = String.format(baseUrl,ConstantWxUtils.WX_APP_ID,redirectUrl,"atguigu");
        return "redirect:" + url;
    }

    @GetMapping("/api/ucenter/wx/callback")
    public String callback(@RequestParam("code") String code, @RequestParam("state") String state, RedirectAttributes redirectAttributes){

        try {
            String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                    "?appid=%s" +
                    "&secret=%s" +
                    "&code=%s" +
                    "&grant_type=authorization_code";
            String accessTokenUrl = String.format(baseAccessTokenUrl,
                    ConstantWxUtils.WX_APP_ID,
                    ConstantWxUtils.WX_APP_SECRET,
                    code);
            String accessToken = HttpClientUtils.get(accessTokenUrl);
            Gson gson = new Gson();
            HashMap accessTokenMap = gson.fromJson(accessToken, HashMap.class);
            String access_token = (String) accessTokenMap.get("access_token");
            String openid = (String) accessTokenMap.get("openid");

            //通过微信access_token查询用户的微信信息
            String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                        "?access_token=%s" +
                        "&openid=%s";
            String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
            String userInfo = HttpClientUtils.get(userInfoUrl);
            HashMap<String,String> userInfoMap = gson.fromJson(userInfo, HashMap.class);
            String nickname = userInfoMap.get("nickname");
            String headimgurl = userInfoMap.get("headimgurl");
            String unionid = userInfoMap.get("unionid");
            String city = userInfoMap.get("city");
            UserLoginWxVo userLoginWxVo = new UserLoginWxVo();
            userLoginWxVo.setUsername(nickname + "_" + RandomUtil.getSixBitRandom());
            userLoginWxVo.setCity(city);
            userLoginWxVo.setSocialWxId(unionid);
            userLoginWxVo.setHeader(headimgurl);
            R r = memberFeignService.wxLogin(userLoginWxVo);
            if (r.getCode() != 0){
                return "redirect:http://auth.gulimall.com/login.html";
            }
            UserLoginWxVo loginUser = r.getData("data", new TypeReference<UserLoginWxVo>() {});
            String loginUserJson = redisTemplate.opsForValue().get(loginUser.getSocialWxId());
            if (loginUserJson == null){
                String jwtToken = JwtUtils.getJwtToken(loginUser.getSocialWxId());
                loginUserJson = JSON.toJSONString(loginUser);
                redisTemplate.opsForValue().set(loginUser.getSocialWxId(), loginUserJson, 30L, TimeUnit.MINUTES);
                redirectAttributes.addAttribute("wxJwtToken", jwtToken);
            }
            return "redirect:http://auth.gulimall.com/wxLogin.html";
        }
        catch (Exception e){
            e.printStackTrace();
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }

    @GetMapping("/wxLogin.html")
    public String addToCartSuccess(@RequestParam(value = "wxJwtToken", required = false) String wxJwtToken, HttpServletResponse response){

        if (!StringUtils.isEmpty(wxJwtToken)){
            Cookie cookie = new Cookie(AuthServiceConstant.LOGIN_USER, wxJwtToken);
            cookie.setDomain("gulimall.com");
            cookie.setMaxAge(AuthServiceConstant.USER_TIMEOUT);
            response.addCookie(cookie);
        }
        return "redirect:http://gulimall.com";

    }

    @RequestMapping(value = "ProxyToAdmin", method = RequestMethod.GET)
    private String ProxyToAdmin() {
        return "redirect:toAdmin";
    }
}
